package cn.hd01.web.controller;

import cn.hd01.repository.entity.*;
import cn.hd01.service.*;
import cn.hd01.util.DictionaryType;
import cn.hd01.util.NetUtil;
import cn.hd01.web.auth.Auth;
import cn.hd01.web.auth.AuthType;
import cn.hd01.web.util.WebHelper;
import cn.hd01.weixin.model.Result;
import cn.hd01.weixin.service.WeixinPayService;
import cn.hd01.weixin.util.WeiXinUtils;
import com.google.common.collect.Maps;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.web.PageableDefault;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.Map;

/**
 * Created by beta.chen
 * Time:2017/5/7 21:19
 */
@Controller
@RequestMapping("/requirement")
@Auth
public class RequirementController {
    private static final Logger logger = LoggerFactory.getLogger(RequirementController.class);

    // 发单定金
    @Value("${requirement.deposits.rmb}")
    private double depositsRmb;

    @Autowired
    private OrderService orderService;

    @Autowired
    private WXAppService appService;

    @Autowired
    private WXOauthService oauthService;

    @Autowired
    private WeixinPayService weixinPayService;

    @Autowired
    private RequirementService requirementService;

    @Autowired
    private FlowService flowService;

    @Autowired
    private DictionaryService dictionaryService;

    @Autowired
    private UploadService uploadService;

    @RequestMapping(path = "/status/{status}", method = RequestMethod.GET)
    public String status(@PathVariable("status") Integer status, Model model){
        model.addAttribute("status", status);
        model.addAttribute("majors", dictionaryService.findByType(DictionaryType.MAJOR));
        model.addAttribute("styles", dictionaryService.findByType(DictionaryType.STYLE));
        model.addAttribute("statusList", dictionaryService.findByType(DictionaryType.REQUIREMENT_STATUS));
        return "requirement/statusList";
    }

    @ResponseBody
    @RequestMapping(path = "/status/list/{status}", method = RequestMethod.GET)
    public Page<Requirement> statusList(@PathVariable("status") Integer status, Requirement requirement, @PageableDefault Pageable pageable){
        requirement.setStatus(status);
        return requirementService.find(requirement, pageable);
    }

    /**
     * 详情信息
     */
    @RequestMapping(path = "/status/{status}/detail/{id}", method = RequestMethod.GET)
    public String detail(@PathVariable("status") Integer status, @PathVariable("id") Integer id, Model model) {
        Requirement r = requirementService.findOne(id);

        model.addAttribute("uploads", uploadService.findByTypeAndRefIdOrderBySortAsc("requirement", id));
        model.addAttribute("products", uploadService.findByTypeAndRefIdOrderBySortAsc("requirement_product", id));
        model.addAttribute("majors", dictionaryService.findByType(DictionaryType.MAJOR));
        model.addAttribute("styles", dictionaryService.findByType(DictionaryType.STYLE));
        model.addAttribute("flows", dictionaryService.findByType(DictionaryType.REQUIREMENT_FLOW));
        if (status == 4){
            model.addAttribute("lastFlow", flowService.findLastFlow(Flow.REQUIREMENT, r.getId()));
        }

        model.addAttribute("r", r);
        return "requirement/detail";
    }


    @RequestMapping(path = "/my", method = RequestMethod.GET)
    public String my(Model model) {
        model.addAttribute("majors", dictionaryService.findByType(DictionaryType.MAJOR));
        model.addAttribute("styles", dictionaryService.findByType(DictionaryType.STYLE));
        model.addAttribute("statusList", dictionaryService.findByType(DictionaryType.REQUIREMENT_STATUS));
        return "requirement/my";
    }

    @ResponseBody
    @RequestMapping(path = "/my/list", method = RequestMethod.GET)
    public Page<Requirement> myList(Requirement requirement, @PageableDefault Pageable pageable) {
        // 只显示自己提单
        User user = WebHelper.currentUser();
        requirement.setOwnerId(user.getId());

        return requirementService.find(requirement, pageable);
    }

    @RequestMapping(path = "/my/add", method = RequestMethod.GET)
    public String addRequirement(Model model) {
        model.addAttribute("majors", dictionaryService.findByType(DictionaryType.MAJOR));
        model.addAttribute("styles", dictionaryService.findByType(DictionaryType.STYLE));
        return "requirement/addRequirement";
    }

    /**
     * 保存发单基本信息
     */
    @ResponseBody
    @RequestMapping(path = "/my/add", method = RequestMethod.POST)
    public int addSave(Requirement requirement) {
        User user = WebHelper.currentUser();
        requirement.setOwnerId(user.getId());
        requirement.setOwnerName(user.getName());
        requirement.setStatus(0);
        requirement.setAlreadyPaid(0.0);
        // 设置定金
        requirement.setDeposits(depositsRmb);

        Requirement r = requirementService.save(requirement);
        return r.getId();
    }

    /**
     * 我的发单 详情页面
     */
    @RequestMapping(path = "/my/detail/{id}", method = RequestMethod.GET)
    public String myDetail(@PathVariable("id") Integer id, Model model) {
        Requirement r = requirementService.findOne(id);

        model.addAttribute("uploads", uploadService.findByTypeAndRefIdOrderBySortAsc("requirement", id));
        model.addAttribute("products", uploadService.findByTypeAndRefIdOrderBySortAsc("requirement_product", id));
        model.addAttribute("majors", dictionaryService.findByType(DictionaryType.MAJOR));
        model.addAttribute("styles", dictionaryService.findByType(DictionaryType.STYLE));
        model.addAttribute("editable", r.getStatus() >= 0 && r.getStatus() <= 1);
        model.addAttribute("flows", dictionaryService.findByType(DictionaryType.REQUIREMENT_FLOW));
        model.addAttribute("lastFlow", flowService.findLastFlow(Flow.REQUIREMENT, r.getId()));

        model.addAttribute("r", r);
        return "requirement/myDetail";
    }

    /**
     * 编辑发单基本信息
     */
    @ResponseBody
    @RequestMapping(path = "/my/save", method = RequestMethod.POST)
    public Result updateSave(Requirement requirement){
        Requirement r = requirementService.getOne(requirement.getId());
        if (r == null){
            return new Result(0, "数据不存在");
        }

        if (r.getStatus()<0 || r.getStatus() > 1){
            return new Result(0, "审核通过, 不可修改数据");
        }

        User user = WebHelper.currentUser();
        requirement.setOwnerId(user.getId());
        requirement.setOwnerName(user.getName());
        requirement.setDeposits(depositsRmb);

        requirementService.save(requirement);
        return new Result(1, "保存成功");
    }


    /**
     * 删除单子
     */
    @ResponseBody
    @RequestMapping(path = "/delete/{id}", method = RequestMethod.GET)
    public void delete(@PathVariable("id") Integer id) {
        requirementService.delete(id);

        uploadService.deleteByTypeAndRefId("requirement", id);
    }

    /**
     * 审核列表页面
     */
    @RequestMapping(path = "/exam", method = RequestMethod.GET)
    public String exam(Model model) {
        model.addAttribute("majors", dictionaryService.findByType(DictionaryType.MAJOR));
        model.addAttribute("styles", dictionaryService.findByType(DictionaryType.STYLE));
        model.addAttribute("statusList", dictionaryService.findByType(DictionaryType.REQUIREMENT_STATUS));
        return "requirement/exam";
    }

    /**
     * 待审核列表
     */
    @ResponseBody
    @RequestMapping(path = "/exam/list", method = RequestMethod.GET)
    public Page<Requirement> examList(Requirement requirement, @PageableDefault Pageable pageable) {
        //只查询待审核列表
        requirement.setStatus(1);
        return requirementService.find(requirement, pageable);
    }


    /**
     * 全部列表
     */
    @ResponseBody
    @RequestMapping(path = "/allList", method = RequestMethod.GET)
    public Page<Requirement> allList(Requirement requirement, @PageableDefault Pageable pageable, Model model) {
        model.addAttribute("majors", dictionaryService.findByType(DictionaryType.MAJOR));
        model.addAttribute("styles", dictionaryService.findByType(DictionaryType.STYLE));
        model.addAttribute("statusList", dictionaryService.findByType(DictionaryType.REQUIREMENT_STATUS));
        return requirementService.find(requirement, pageable);
    }

    /**
     * 审核列表 详情页面
     */
    @RequestMapping(path = "/exam/detail/{id}", method = RequestMethod.GET)
    public String examDetail(@PathVariable("id") Integer id, Model model) {
        Requirement r = requirementService.findOne(id);
        
        model.addAttribute("uploads", uploadService.findByTypeAndRefIdOrderBySortAsc("requirement", id));
        model.addAttribute("majors", dictionaryService.findByType(DictionaryType.MAJOR));
        model.addAttribute("styles", dictionaryService.findByType(DictionaryType.STYLE));

        model.addAttribute("r", r);
        return "requirement/examDetail";
    }

    /**
     * 审核请求
     */
    @ResponseBody
    @RequestMapping(path = "/exam", method = RequestMethod.POST)
    public Result examRequirement(@RequestParam("id") Integer id, @RequestParam("status") Integer status, @RequestParam("price") Double price, @RequestParam("pick") Boolean pick) {
        Requirement r = requirementService.getOne(id);
        if (null == status || null == price){
            return new Result(0, "审核失败，参数错误");
        }

        if (status == 5 && price < depositsRmb){
            return new Result(0, "审核失败，价格错误");
        }

        if (!pick){
            if (requirementService.examRequirement(r.getId(), status, price) == 1){
                return new Result(1, "审核成功");
            }
            return new Result(0, "审核失败");
        } else{
            // 直接接单
            User user = WebHelper.currentUser();
            if (user.getId() == r.getOwnerId()){
                return new Result(0, "审核接单失败，发单人不允许自己接单");
            }

            if (requirementService.examAndPick(r.getId(), user, price) == 1){
                return new Result(1, "审核接单成功");
            }

            return new Result(0, "审核接单失败");
        }
    }

    /**
     * 接单列表页面
     */
    @RequestMapping(path = "/pick", method = RequestMethod.GET)
    public String pick(Model model) {
        model.addAttribute("majors", dictionaryService.findByType(DictionaryType.MAJOR));
        model.addAttribute("styles", dictionaryService.findByType(DictionaryType.STYLE));
        model.addAttribute("statusList", dictionaryService.findByType(DictionaryType.REQUIREMENT_STATUS));
        return "requirement/pick";
    }

    /**
     * 接单列表
     */
    @ResponseBody
    @RequestMapping(path = "/pick/list", method = RequestMethod.GET)
    public Page<Requirement> pickList(Requirement requirement, @PageableDefault Pageable pageable) {
        // 只显示自己接单
        User user = WebHelper.currentUser();
        requirement.setDesignerId(user.getId());

        return requirementService.find(requirement, pageable);
    }

    /**
     * 接单大厅列表，显示待接单列表 状态为 2-审核通过
     */
    @ResponseBody
    @RequestMapping(path = "/pick/allList", method = RequestMethod.GET)
    public Page<Requirement> pickAllList(Requirement requirement, @PageableDefault Pageable pageable) {
        // 审核通过单子
        requirement.setStatus(2);
        return requirementService.find(requirement, pageable);
    }

    /**
     * 我的接单 详情页面
     */
    @RequestMapping(path = "/pick/detail/{id}", method = RequestMethod.GET)
    public String pickDetail(@PathVariable("id") Integer id, Model model) {
        Requirement r = requirementService.findOne(id);

        model.addAttribute("uploads", uploadService.findByTypeAndRefIdOrderBySortAsc("requirement", id));
        model.addAttribute("products", uploadService.findByTypeAndRefIdOrderBySortAsc("requirement_product", id));
        model.addAttribute("majors", dictionaryService.findByType(DictionaryType.MAJOR));
        model.addAttribute("styles", dictionaryService.findByType(DictionaryType.STYLE));
        model.addAttribute("flows", dictionaryService.findByType(DictionaryType.REQUIREMENT_FLOW));
        model.addAttribute("lastFlow", flowService.findLastFlow(Flow.REQUIREMENT, r.getId()));

        model.addAttribute("r", r);
        return "requirement/pickDetail";
    }

    /**
     * 设计师接单
     */
    @ResponseBody
    @RequestMapping(path = "/pick/{id}", method = RequestMethod.POST)
    public int pickRequirement(@PathVariable("id") Integer id) {
        User user = WebHelper.currentUser();
        Requirement r = requirementService.getOne(id);
        if (r == null){
            return 0;
        }

        if (r.getOwnerId().equals(user.getId())){
            return 0;
        }

        return requirementService.pick(id, user);
    }

    /**
     * 接单提交完成
     */
//    @ResponseBody
//    @RequestMapping(path = "/pick/commit", method = RequestMethod.POST)
//    public void pickCommit(@RequestParam("id") Integer id) {
//        Requirement r = requirementService.getOne(id);
//
//        requirementService.pickCommit(r.getId());
//    }

    /**
     * 验收订单
     */
//    @ResponseBody
//    @RequestMapping(path = "/received/{id}", method = RequestMethod.POST)
//    public void receivedRequirement(@PathVariable("id") Integer id){
//        Requirement r = requirementService.getOne(id);
//
//        requirementService.receivedRequirement(r.getId());
//    }

    @ResponseBody
    @RequestMapping(path = "/flow/{id}", method = RequestMethod.POST)
    public Result flow(@PathVariable("id") Integer id){
        User user = WebHelper.currentUser();
        Requirement r = requirementService.findOne(id);

        List<Dictionary> flowList = dictionaryService.findByType(DictionaryType.REQUIREMENT_FLOW);
        Flow lastFlow = flowService.findLastFlow(Flow.REQUIREMENT, r.getId());
        if (lastFlow == null){
            if (!user.getId().equals(r.getDesignerId())){
                return new Result(0, "当前节点不允许操作");
            }
        } else {
            if (flowList.get(flowList.size() -1).getName().equals(lastFlow.getName())){
                return new Result(0, "当前节点不允许操作");
            }

            if (lastFlow.getAdderId().equals(user.getId())){
                return new Result(0, "当前节点不允许操作");
            }
        }


        flowService.save(new Flow(Flow.REQUIREMENT, r.getId(), getFlowName(flowList, lastFlow), user));

        if (flowList.size() == flowService.findFlows(Flow.REQUIREMENT, r.getId()).size()){
            requirementService.receivedRequirement(r.getId());
        }

        return new Result(1, "提交成功");
    }

    private String getFlowName(List<Dictionary> list, Flow lastFlow){
        if (lastFlow == null){
            return list.get(0).getName();
        }

        int index = 0;
        for (int i = 0; i < list.size(); i++) {
            if (list.get(i).getName().equals(lastFlow.getName())){
                index = i;
                break;
            }
        }

        return list.get(Math.min(list.size()-1, index + 1)).getName();
    }

    @ResponseBody
    @RequestMapping(path = "/payBalance/{id}", method = RequestMethod.POST)
    public Result payBalance(@PathVariable("id") Integer id, HttpServletRequest request){
        User user = WebHelper.currentUser();
        if (null == user.getOauthId()){
            return new Result(0, "该账号请先关注微信公众号");
        }

        Requirement r = requirementService.getOne(id);
        if (r.getStatus() != 5){
            return new Result(0, "订单重复支付");
        }

        Order order = orderService.findByTypeAndProductId(Order.REQUIREMENT_BALANCE, r.getId().toString());
        if (order == null){
            order = orderService.save(Order.createOrder(user, Order.REQUIREMENT_BALANCE, (long)(r.getPrice() * 100 - r.getDeposits() * 100), r.getId().toString()));
        }
        if (order.hasPay()){
            return new Result(0, "订单已经支付");
        }

        String notifyUrl = WebHelper.basePath() + "/requirement/payNotify";
        return unifiedOrder(request, user, order, notifyUrl, "发单尾款");
    }

    @ResponseBody
    @RequestMapping(path = "/payDeposits/{id}", method = RequestMethod.POST)
    public Result payDeposits(@PathVariable("id") Integer id, HttpServletRequest request){
        User user = WebHelper.currentUser();
        if (null == user.getOauthId()){
            return new Result(0, "该账号请先关注微信公众号");
        }

        Requirement r = requirementService.getOne(id);
        if (r.getStatus() != 0){
            return new Result(0, "订单重复支付");
        }

        Order order = orderService.findByTypeAndProductId(Order.REQUIREMENT_DEPOSITS, r.getId().toString());
        if (order == null){
            order = orderService.save(Order.createOrder(user, Order.REQUIREMENT_DEPOSITS, (long)(r.getDeposits() * 100), r.getId().toString()));
        }
        if (order.hasPay()){
            return new Result(0, "订单已经支付");
        }

        String notifyUrl = WebHelper.basePath() + "/requirement/payNotify";
        return unifiedOrder(request, user, order, notifyUrl, "发单定金");
    }

    private Result unifiedOrder(HttpServletRequest request, User user, Order order, String notifyUrl, String body){
        WXOauth wxOauth = oauthService.findOne(user.getOauthId());
        if (wxOauth == null){
            return new Result(0, "该账号请先关注微信公众号");
        }

        WXApp app = appService.findByWeixinId(wxOauth.getWeixinId());

        //构建微信统一下单需要的参数
        Map<String, Object> map = Maps.newHashMap();
        map.put("remoteIp", NetUtil.getRemoteAddrIp(request));//请求Ip地址
        map.put("body", body); // 商品描述
        map.put("tradeType", WeiXinUtils.TRADE_TYPE_NATIVE); // 公众号支付方式

        //调用统一下单service
        Map<String, Object> resultMap = weixinPayService.unifiedOrder(app, notifyUrl, order, map);

        String returnCode = (String) resultMap.get("return_code");//通信标识
        String resultCode = (String) resultMap.get("result_code");//交易标识
        //只有当returnCode与resultCode均返回“success”，才代表微信支付统一下单成功
        if (WeiXinUtils.RETURN_SUCCESS.equals(returnCode) && WeiXinUtils.RETURN_SUCCESS.equals(resultCode)) {
            // 二维码链接 code_url
            String codeUrl = (String)resultMap.get("code_url");

            String qrcodeBase64 = weixinPayService.generateQrcodeToBase64(codeUrl);
            if (qrcodeBase64 == null){
                return new Result(0, "获取微信二维码失败");
            }

            return new Result(1, "data:image/png;base64," + qrcodeBase64);
        }
        else {
            logger.error("微信统一下单失败,订单编号:" + order.getOrderId() + ",失败原因:" + resultMap.get("err_code_des") + ", 描述:" + resultMap.get("return_msg"));
            return new Result(0, "微信下单失败");//支付下单失败，重定向至订单列表
        }
    }

    /**
     * 提交支付后的微信异步返回接口
     */
    @RequestMapping(value = "/payNotify")
    @Auth(AuthType.OFF)
    public void payNotify(HttpServletRequest request, HttpServletResponse response) {
        try {
            Map<String, Object> resultMap = WeiXinUtils.parseXml(request.getInputStream());
            String orderId = (String) resultMap.get("out_trade_no");
            String return_code = (String) resultMap.get("return_code");
            String sign = (String) resultMap.get("sign");
            String mch_id = (String) resultMap.get("mch_id");
            String totalFee = (String) resultMap.get("total_fee");

            WXApp app = appService.findByMchId(mch_id);
            if (app == null) {
                response.getWriter().write(WeiXinUtils.payNotifyReturn("FAIL", "商户不存在"));
                return;
            }

            String expectSign = WeiXinUtils.getSign(resultMap, app.getShKey());
            if (!sign.equals(expectSign)) {
                response.getWriter().write(WeiXinUtils.payNotifyReturn("FAIL", "签名校验失败"));
                return;
            }

            if (return_code.equals("SUCCESS")) {
                orderService.updateStatusByOrderId(1, orderId);

                Order order = orderService.findByOrderId(orderId);
                if (order.getType() == Order.REQUIREMENT_DEPOSITS){
                    requirementService.payDepositsSuccess(Integer.parseInt(order.getProductId()), Integer.parseInt(totalFee));
                } else if(order.getType() == Order.REQUIREMENT_BALANCE){
                    requirementService.payBalanceSuccess(Integer.parseInt(order.getProductId()), Integer.parseInt(totalFee));
                } else{
                    logger.error("微信回调，订单类型未处理:{}", order.getType());
                }
            } else {
                //支付失败的业务逻辑，先记录日志吧
                logger.error("订单支付失败:{}", orderId);
            }

            //通知微信.异步确认成功
            response.getWriter().write(WeiXinUtils.payNotifyReturn("SUCCESS", ""));
        } catch (Exception e) {
            logger.error("微信回调接口出现错误：", e);
            try {
                response.getWriter().write(WeiXinUtils.payNotifyReturn("FAIL", "error"));
            } catch (IOException e1) {
                e1.printStackTrace();
            }
        }
    }

}
